﻿using System;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace CID.Tests.Support.Configuration.Database
{
    class ScriptExecuter : IDisposable
    {
        private static readonly Regex ScriptSplitterRegex = new Regex(@"^\s*GO\s*$", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled);
        private SqlConnection connection;
        private Func<string, string> getVariableDefaultValue;

        public ScriptExecuter(string connectionString, Func<string, string> getVariableDefaultValue)
        {
            this.getVariableDefaultValue = getVariableDefaultValue;
            connection = new SqlConnection(connectionString);
            connection.Open();
        }

        public void Dispose()
        {
            if (connection != null)
            {
                connection.Close();
                connection.Dispose();
                connection = null;
            }
        }

        public void Execute(string scriptPath)
        {
            foreach (string scriptStatement in GetScriptStatements(scriptPath))
                ExecuteNonQuery(scriptStatement);
        }

        private string[] GetScriptStatements(string scriptPath)
        {
            return ScriptSplitterRegex.Split(ReplaceSQLCMDCommands(scriptPath));
        }

        private string ReplaceSQLCMDCommands(string filePath)
        {
            using (StreamReader sr = new StreamReader(filePath))
            {
                StringBuilder sb = new StringBuilder(sr.ReadToEnd());
                Regex setVarCommandRegex = new Regex("^:setvar ([^\\s]*) \"(.*)\"", RegexOptions.Multiline);
                foreach (Match match in setVarCommandRegex.Matches(sb.ToString()))
                {
                    string variableName = match.Groups[1].Captures[0].Value;
                    string variableValue = getVariableDefaultValue(variableName) ?? match.Groups[2].Captures[0].Value;

                    sb.Replace(String.Format("$({0})", variableName), variableValue);
                }

                Regex otherCommandsRegex = new Regex("^:(.*)", RegexOptions.Multiline);
                foreach (Match match in otherCommandsRegex.Matches(sb.ToString()))
                    sb.Replace(match.Groups[0].Captures[0].Value, String.Empty);

                return sb.ToString();
            }
        }

        private void ExecuteNonQuery(string statement)
        {
            if (!String.IsNullOrEmpty(statement))
            {
                using (IDbCommand command = connection.CreateCommand())
                {
                    command.CommandText = statement;
                    command.CommandType = CommandType.Text;
                    command.ExecuteNonQuery();
                }
            }
        }
    }
}
